using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 保证任意一个节点总是同时存在于MainChain和SubChain两个链表中。并且节点从任意一个链表中删除时，另一个链表中也会同步删除
/// SubChianDict中保存着这个粒子上次被使用时的序列化ID
/// 如果SubChainDict中没有这个ID，则从MainChain中获取一个最久没有使用的粒子
/// 如果SubChainDict中有这个ID，则直接从SubChain中获取一个粒子
/// 这样的话，从SubChain获取的粒子不需要重新赋值序列化内容
/// </summary>
public class ParticleSystemPool : MonoBehaviour
{
    public static ParticleSystemPool Instance { get; private set; }

    public static string NakedParticleName = "NakedParticle";

    ParticleSystemPoolNodeQueue mainChain;

    Dictionary<ulong, ParticleSystemPoolNodeQueue> subChainDict;

    void Awake()
    {
        Instance = this;
        DontDestroyOnLoad(gameObject);

        mainChain = new ParticleSystemPoolNodeQueue(true);
        subChainDict = new Dictionary<ulong, ParticleSystemPoolNodeQueue>();
        // 预加载一些裸粒子，除非同屏粒子数大于这个数量，否则用不完
        // 仅进行预加载的演示，不推荐在这里进行预加载
        Preload(100);
    }

    public void Preload(int count)
    {
        for (int i = 0; i < count; i++)
        {
            var node = GetNewNode();
            Put(node);
        }
    }

    public int GetTempCount(ulong id)
    {
        if (subChainDict.TryGetValue(id, out ParticleSystemPoolNodeQueue subChain))
        {
            return subChain.Count;
        }
        return 0;
    }

    void Oestroy()
    {
        Instance = null;
    }

    public void Put(ParticleSystemPoolNode node)
    {
        if (Instance == null)
        {
            Debug.LogWarning("ParticleSystemPool Instance is null, cannot put particle system node.");
            return;
        }
        if (node == null || node.ParticleSystem == null)
        {
            Debug.LogWarning("ParticleSystemPoolNode is null or ParticleSystem is null, cannot put into pool.");
            return;
        }
        mainChain.Enqueue(node);
        if (!subChainDict.TryGetValue(node.LastUseId, out ParticleSystemPoolNodeQueue subChain))
        {
            subChain = new ParticleSystemPoolNodeQueue(false);
            subChainDict[node.LastUseId] = subChain;
        }
        subChain.Enqueue(node);
        node.ParticleSystem.gameObject.SetActive(false);
        node.ParticleSystem.transform.SetParent(this.transform, true);
        node.ParticleSystem.transform.localPosition = Vector3.zero;
        node.ParticleSystem.transform.localRotation = Quaternion.identity;
        node.ParticleSystem.transform.localScale = Vector3.one;
    }

    public ParticleSystemPoolNode Get(ulong id)
    {
        // 子链表发现了目标粒子，直接使用，这个粒子可以不用重新赋值序列化内容
        if (subChainDict.TryGetValue(id, out ParticleSystemPoolNodeQueue subChain) && subChain.Count > 0)
        {
            ParticleSystemPoolNode node = subChain.Peek();
            subChain.Remove(node);
            mainChain.Remove(node);
            return node;
        }
        // 子链表没有目标粒子，只能从主链表获取一个最久没有使用的粒子，这个粒子只能重新赋值序列化内容
        else if (mainChain.Count > 0)
        {
            ParticleSystemPoolNode node = mainChain.Peek();
            mainChain.Remove(node);
            var forSubChain = subChainDict[node.LastUseId];
            forSubChain.Remove(node);
            return node;
        }
        else
        {
            return GetNewNode();
        }
    }

    public ParticleSystemPoolNode GetNewNode()
    {
        var particleGo = new GameObject(NakedParticleName);
        var newNode = particleGo.AddComponent<ParticleSystemPoolNode>();
        var particleSystem = particleGo.AddComponent<ParticleSystem>();
        var particleRenderer = particleGo.GetComponent<ParticleSystemRenderer>();
        newNode.ParticleSystem = particleSystem;
        newNode.ParticleRenderer = particleRenderer;
        newNode.ParticleTransform = particleGo.transform;
        return newNode;
    }
}
